/*
 * config.c
 *
 *  Created on: 14/09/2011
 *      Author: MadeyMaga
 */

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

//#include "log.h"
#include "config.h"


/*cantidad de digitos significativos del nombre de una variable*/
#define DATA_NAME_LEN 25


typedef enum
{
	D_INT8 = 0,
	D_UINT8 = 1,
	D_INT16 = 2,
	D_UINT16 = 3,
	D_INT32 = 4,
	D_UINT32 = 5,
	D_STR = 6,
	D_FIRST = D_INT8,
	D_LAST = D_STR + 1,
	D_ERROR = 7
} DATA_TYPE;

typedef struct
{
	char 	  varName[DATA_NAME_LEN];
	DATA_TYPE type;
	union{
		char 			d_int8;
		unsigned char	d_uint8;
		short 			d_int16;
		unsigned short 	d_uint16;
		int 			d_int32;
		unsigned int 	d_uint32;
		char 			*d_str;
	} data;
} config_data_t;

static char data_names[7][8] = {"int8 ", "uint8 ", "int16 ", "uint16 ", "int32 ", "uint32 ", "string "};


static config_data_t* 	__data = NULL;
static int				__datacount = 0;
static int				__loaded = 0;


static int cargarData(char *data);
static void cleanUpBufferComents(char *iBuffer);
static DATA_TYPE getDataType(char *line);
static void addConfig(char *linea, DATA_TYPE dType);

int cargarConfig(char *fileName)
{
	FILE *file;
	char buffer[512], *content = NULL;
	size_t leido, total = 0;
	int retval = 0;

	if(NULL == (file = fopen(fileName, "rb")))
	{
		//log_error(log, "Thread-1", "Message error: %s", "Imposible abrir el archivo de configuracion especificado");
		return 1;
	}

	do
	{
		leido = fread(buffer, 1, 512, file);

		content = (char*)realloc(content, total + leido + 1);

		memcpy((content + total), buffer, leido);

		total += leido;
	}while(512 == leido);

	content[total] = '\0';

	cleanUpBufferComents(content);

	if((retval = cargarData(content)))
	{
		//t_log* log = log_create("Planificador", "log.txt", WARNING, M_CONSOLE_ENABLE);
		//log_warning(log, "Thread-1", "Message Warning: %s", "El archivo de configuracion ya esta cargado. Llame antes a cleanUpBufferComents().");
	}

	if(content != NULL)
		free(content);

	fclose(file);

	return retval;
}

static void cleanUpBufferComents(char *iBuffer)
{
	int r = 0, w = 0,lc = 0, bc = 0;


	do{
		if((!lc) && (!bc))
		{
			if(iBuffer[r] == '#')
			{
				if(iBuffer[r+1] == '#')
					lc = 1;
				else if(iBuffer[r+1] == '{')
					bc = 1;
			}else{
				iBuffer[w++] = iBuffer[r];
			}
		}else{
			if(lc)
				if(iBuffer[r] == '\n')
					lc = 0;
			if(bc)
				if(iBuffer[r] == '}')
					if(iBuffer[r+1] == '#')
					{
						bc = 0;
						r++;
					}
		}

		r++;
	}while(iBuffer[r] != '\0');

	iBuffer[w] = '\0';

}


static void addConfig(char *linea, DATA_TYPE dType)
{
	char varname[50], value[150];
	//char log_msg[512];


	sscanf(linea, "%*s%s%s", varname, value);

	__data = (config_data_t*) realloc(__data, sizeof(config_data_t) * (__datacount + 1));

	memset(__data[__datacount].varName, 0 , DATA_NAME_LEN);

	memcpy(__data[__datacount].varName, varname, DATA_NAME_LEN);

	__data[__datacount].type = dType;

	switch(dType)
	{
		case D_INT8:
			__data[__datacount].data.d_int8 = atoi(value);
#ifdef LOG_H_

			log_info(log, "Thread-1", "Message info: %s", "Se cargo una variable del archive de configuracion.");

#endif
			break;
		case D_UINT8:
			__data[__datacount].data.d_uint8 = (unsigned char)strtoul(value, NULL, 0);
#ifdef LOG_H_

			log_info(log, "Message info: %s", "Se cargo una variable del archivo de configuracion.");
#endif
			break;
		case D_INT16:
			__data[__datacount].data.d_int16 = atoi(value);
#ifdef LOG_H_

			log_info(log, "thread-1", "Message info: %s", "Se cargo una variable del archivo de configuracion");
#endif
			break;
		case D_UINT16:
			__data[__datacount].data.d_uint16 = (unsigned short)strtoul(value, NULL, 0);
#ifdef LOG_H_

			log_info(log, "Thread-1", "Message info: %s", "Se cargo una variable del archivo de configuracion");
#endif
			break;
		case D_INT32:
			__data[__datacount].data.d_int32 = atol(value);
#ifdef LOG_H_

			log_info(log, "Thread-1", "Message info: %s", "Se cargo una variable del archivo de configuracion");
#endif
			break;
		case D_UINT32:
			__data[__datacount].data.d_uint32 = strtoul(value, NULL, 0);
#ifdef LOG_H_

			log_info(log, "Thread-1", "Message info: %s", "Se cargo una variable del archivo de configuracion");
#endif
			break;
		case D_STR:
			__data[__datacount].data.d_str = (char*)malloc(strlen(value) + 1);
			strcpy(__data[__datacount].data.d_str, value);
#ifdef LOG_H_

			log_info(log, "Thread-1", "Message info: %s", "Se cargo una variable del archivo de configuracion");
#endif
			break;
		default:
			break;
	}

	__datacount++;
}


int getConfig(char *varName, void *data)
{
	char 			*int8p, *str;
	unsigned char 	*uint8p;
	short 			*int16p;
	unsigned short 	*uint16p;
	int 			*int32p, n = 0, f = 0;
	unsigned int 	*uint32p;


	while((!f) && (n < __datacount))
	{
		if(!strcmp(varName, __data[n].varName))
		{
			f = 1;
		} else
			n++;
	}


	if(n == __datacount)
		return -1;

	switch(__data[n].type)
	{
		case D_INT8:
			int8p = (char *)data;
			*int8p = __data[n].data.d_int8;
			break;
		case D_UINT8:
			uint8p = (unsigned char *)data;
			*uint8p = __data[n].data.d_uint8;
			break;
		case D_INT16:
			int16p = (short *)data;
			*int16p = __data[n].data.d_int16;
			break;
		case D_UINT16:
			uint16p = (unsigned short *)data;
			*uint16p = __data[n].data.d_uint16;
			break;
		case D_INT32:
			int32p = (int *)data;
			*int32p = __data[n].data.d_int32;
			break;
		case D_UINT32:
			uint32p = (unsigned int *)data;
			*uint32p = __data[n].data.d_uint32;
			break;
		case D_STR:
			str = (char *)data;
			strcpy(str, __data[n].data.d_str);
			break;
		default:
			break;
	}

	return 0;
}


static DATA_TYPE getDataType(char *line)
{
	DATA_TYPE dtype, retval;
	int found = 0;

	if(line[0] == '\n')
		return D_ERROR; /*si el tipo de dato esta vacio*/

	for(dtype = D_FIRST; (dtype != D_LAST) && (!found); dtype++)
	{
		if(line == strstr(line, data_names[dtype]))
		{
			retval = dtype;
			found = 1;
		}
	}

	if(found)
		return retval;

	return D_ERROR;
}


static int cargarData(char *data)
{
	char *tok;
	DATA_TYPE tipoData;

	if(__loaded)
		return 1;

	tok = strtok(data, "\n");

	do
	{
		tipoData = getDataType(tok);

		if(tipoData != D_ERROR)
			addConfig(tok, tipoData);

		tok = strtok(NULL, "\n");
	}while(tok != NULL);

	__loaded = 1;

	return 0;
}


void clearConfig(void)
{
	int i;

	if(!__loaded)
		return ;

	for(i = 0; i < __datacount; i++)
	{
		if(__data[i].type == D_STR)
			if(NULL != __data[i].data.d_str)
				free(__data[i].data.d_str);
	}

	if(NULL != __data)
	{
		free(__data);
		__data = NULL;
	}

	__datacount  = 0;

	__loaded = 0;

}

